---
title: Writing your own plugins
---

import { Aside } from '@astrojs/starlight/components';


With Orama `v2.0.0-beta.5`, we introduced the new plugin system. This allows you to write your own plugins and use them in your Orama project.

The Orama plugin system is meant to replace the old hooks system, which is now deprecated.

If you had any custom hook, it would be incredibly easy to migrate it to a plugin, as the APIs are 100% backward compatible.

## Creating a plugin

A plugin is essentially a JavaScript object with a `name` and a series of hook functions.

An example plugin could look like this:

```js
function loggerPlugin() {
  return {
    name: "logger",
    beforeSearch: (orama, query) => {
      console.log(
        `About to search for ${query.term} on Orama instance ${orama.id}`
      );
    },
  };
}
```

And you can then use it in your Orama instance like this:

```js
import { create, insert, search } from "@orama/orama";

function loggerPlugin() {
  return {
    name: "logger",
    beforeSearch: (orama, query) => {
      console.log(
        `About to search for ${query.term} on Orama instance ${orama.id}`
      );
    },
  };
}

const orama = create({
  id: "my-instance", // Remember, IDs are automatically generated if not provided
  schema: {
    name: "string",
  },
  plugins: [loggerPlugin()],
});

await insert(orama, { name: "John" });
await search(orama, { term: "John" });

// Console logs: "About to search for john on Orama instance my-instance"
```

Every plugin should have:

- A `name` property, which is a string (**mandatory**)
- Any hook function you want to use (**optional**)

## Plugin hooks

With `v2.0.0-beta.5`, we essentially moved the hooks from the `components` property of the Orama instance to the `plugins` property.

The available hooks are:


  - [`beforeInsert`](#beforeinsert)
  - [`afterInsert`](#afterinsert)
  - [`beforeRemove`](#beforeremove)
  - [`afterRemove`](#afterremove)
  - [`beforeUpdate`](#beforeupdate)
  - [`afterUpdate`](#afterupdate)
  - [`beforeSearch`](#beforesearch)
  - [`afterSearch`](#aftersearch)
  - [`beforeInsertMultiple`](#beforeinsertmultiple)
  - [`afterInsertMultiple`](#afterinsertmultiple)
  - [`beforeRemoveMultiple`](#beforeremovemultiple)
  - [`afterRemoveMultiple`](#afterremovemultiple)
  - [`beforeUpdateMultiple`](#beforeupdatemultiple)
  - [`afterUpdateMultiple`](#afterupdatemultiple)

### `beforeInsert`

Runs before an insert operation. Receives the Orama instance, the document ID, and the entire document to be inserted as arguments.

```js
function beforeInsertPluginExample() {
  return {
    name: "before-insert-plugin",
    beforeInsert: (orama, id, document) => {
      console.log("Orama instance: ", orama);
      console.log("Document id: ", id);
      console.log("Document to be inserted: ", document);
    },
  };
}
```

### `afterInsert`

Runs after an insert operation. Receives the Orama instance, the document ID, and the entire document as arguments.

```js
function afterInsertPluginExample() {
  return {
    name: "after-insert-plugin",
    afterInsert: (orama, id, document) => {
      console.log("Orama instance: ", orama);
      console.log("Document id: ", id);
      console.log("Document inserted: ", document);
    },
  };
}
```

### `beforeRemove`

Runs before a remove operation. Receives the Orama instance and the document ID to be removed as arguments.

```js
function beforeRemovePluginExample() {
  return {
    name: "before-remove-plugin",
    beforeRemove: (orama, id) => {
      console.log("Orama instance: ", orama);
      console.log("Document id: ", id);
    },
  };
}
```

### `afterRemove`

Runs after a remove operation. Receives the Orama instance and the document ID removed as arguments.

```js
function afterRemovePluginExample() {
  return {
    name: "after-remove-plugin",
    afterRemove: (orama, id) => {
      console.log("Orama instance: ", orama);
      console.log("Document id: ", id);
    },
  };
}
```

### `beforeUpdate`

Runs before an update operation. Receives the Orama instance and the document ID to be updated as arguments.

```js
function beforeUpdatePluginExample() {
  return {
    name: "before-update-plugin",
    beforeUpdate: (orama, id) => {
      console.log("Orama instance: ", orama);
      console.log("Document id: ", id);
    },
  };
}
```

### `afterUpdate`

Runs after an update operation. Receives the Orama instance and the document ID as arguments.

```js
function afterUpdatePluginExample() {
  return {
    name: "after-update-plugin",
    afterUpdate: (orama, id) => {
      console.log("Orama instance: ", orama);
      console.log("Document id: ", id);
    },
  };
}
```

### `beforeSearch`

Runs before a search operation. Receives the Orama instance and the query object as arguments.

```js
function beforeSearchPluginExample() {
  return {
    name: "before-search-plugin",
    beforeSearch: (orama, query) => {
      console.log("Orama instance: ", orama);
      console.log("Query: ", query);
    },
  };
}
```

### `afterSearch`

Runs after a search operation. Receives the Orama instance, the query object, and the search results as arguments.

```js
function afterSearchPluginExample() {
  return {
    name: "after-search-plugin",
    afterSearch: (orama, query, result) => {
      console.log("Orama instance: ", orama);
      console.log("Query: ", query);
      console.log("Search result: ", result);
    },
  };
}
```

### `beforeInsertMultiple`

Runs before an `insertMultiple` operation. Receives the Orama instance and the documents to be inserted as arguments.

<Aside type="caution">
Since the `insertMultiple` operation is calling the `insert` operation underneath,
the `beforeInsertMultiple` hook will be called for each document. \
 If there's an existing `beforeInsert` hook in the plugin, it will be called for each document as well.
</Aside>

```js
function beforeInsertMultiplePluginExample() {
  return {
    name: "before-insert-multiple-plugin",
    beforeInsertMultiple: (orama, documents) => {
      console.log("Orama instance: ", orama);
      console.log("Documents to be inserted: ", documents);
    },
  };
}
```

### `afterInsertMultiple`

Runs after an `insertMultiple` operation. Receives the Orama instance and the documents inserted as arguments.

<Aside type="caution">
Since the `insertMultiple` operation is calling the `insert` operation underneath,
the `afterInsertMultiple` hook will be called for each document. \
 If there's an existing `afterInsert` hook in the plugin, it will be called for each document as well.
</Aside>

```js
function afterInsertMultiplePluginExample() {
  return {
    name: "after-insert-multiple-plugin",
    afterInsertMultiple: (orama, documents) => {
      console.log("Orama instance: ", orama);
      console.log("Documents inserted: ", documents);
    },
  };
}
```

### `beforeRemoveMultiple`

Runs before a `removeMultiple` operation. Receives the Orama instance and the IDs of the documents to be removed as arguments.

<Aside type="caution">
Since the `removeMultiple` operation is calling the `remove` operation underneath,
the `beforeRemoveMultiple` hook will be called for each document. \
 If there's an existing `beforeRemove` hook in the plugin, it will be called for each document as well.
</Aside>

```js
function beforeRemoveMultiplePluginExample() {
  return {
    name: "before-remove-multiple-plugin",
    beforeRemoveMultiple: (orama, ids) => {
      console.log("Orama instance: ", orama);
      console.log("Document IDs to be removed: ", ids);
    },
  };
}
```

### `afterRemoveMultiple`

Runs after a `removeMultiple` operation. Receives the Orama instance and the IDs of the documents removed as arguments.

<Aside type="caution">
Since the `removeMultiple` operation is calling the `remove` operation underneath,
the `afterRemoveMultiple` hook will be called for each document. \
 If there's an existing `afterRemove` hook in the plugin, it will be called for each document as well.
</Aside>

```js
function afterRemoveMultiplePluginExample() {
  return {
    name: "after-remove-multiple-plugin",
    afterRemoveMultiple: (orama, ids) => {
      console.log("Orama instance: ", orama);
      console.log("Document IDs removed: ", ids);
    },
  };
}
```

### `beforeUpdateMultiple`

Runs before an `updateMultiple` operation. Receives the Orama instance and the IDs of the documents to be updated as arguments.

<Aside type="caution">
Since the `updateMultiple` operation is calling the `update` operation underneath,
the `beforeUpdateMultiple` hook will be called for each document. \
 If there's an existing `beforeUpdate` hook in the plugin, it will be called for each document as well.

Also, consider that the `update` operation is a shorthand for the `remove` and `insert` operations. \
 This means that the `beforeRemove` and `beforeInsert` hooks will be called for each document as well.
</Aside>

```js
function beforeUpdateMultiplePluginExample() {
  return {
    name: "before-update-multiple-plugin",
    beforeUpdateMultiple: (orama, ids) => {
      console.log("Orama instance: ", orama);
      console.log("Document IDs to be updated: ", ids);
    },
  };
}
```

### `afterUpdateMultiple`

Runs after an `updateMultiple` operation. Receives the Orama instance and the IDs of the documents updated as arguments.

<Aside type="caution">
Since the `updateMultiple` operation is calling the `update` operation underneath,
the `afterUpdateMultiple` hook will be called for each document. \
 If there's an existing `afterUpdate` hook in the plugin, it will be called for each document as well.

Also, consider that the `update` operation is a shorthand for the `remove` and `insert` operations. \
 This means that the `afterRemove` and `afterInsert` hooks will be called for each document as well.
</Aside>

```js
function afterUpdateMultiplePluginExample() {
  return {
    name: "after-update-multiple-plugin",
    afterUpdateMultiple: (orama, ids) => {
      console.log("Orama instance: ", orama);
      console.log("Document IDs updated: ", ids);
    },
  };
}
```

## Migrating from hooks to plugins

If you were using the old hooks system, you can easily migrate to the new plugin system by moving your hooks to a single plugin.

For instance, if you had a `beforeInsert` hook, you can migrate it to a plugin like this:

```diff
import { create } from '@orama/orama'

const db = await create({
  schema: {
    name: 'string'
  },
- components: {
-   beforeInsert: (orama, id, document) => {
-     console.log('Orama instance: ', orama)
-     console.log('Document id: ', id)
-     console.log('Document to be inserted: ', document)
-   }
- }
+ plugins: [
+   {
+     name: 'before-insert-plugin',
+     beforeInsert: (orama, id, document) => {
+       console.log('Orama instance: ', orama)
+       console.log('Document id: ', id)
+       console.log('Document to be inserted: ', document)
+     }
+   }
+ ]
})
```

Types, behavior, and arguments are 100% backward compatible, so you don't need to change anything else.
